package com.leyou.order.service;

import com.leyou.common.auth.entity.UserHolder;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.orderLogisticsMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.clent.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.rmi.runtime.Log;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author syf
 * @version 1.0
 * @date 2019/08/18 16:35
 * @Description TODO:
 */
@Slf4j
@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private orderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private IdWorker idWorker;//雪花算法

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;;

    private static String WX_PAY_URL="WX:PAY:URL";
    /**
     * 生成订单
     */
    public Long cartOrderId(OrderDTO orderDTO) {
        try {
            //创建订单对象
            Order order = new Order();
            //创建订单详情列表
            ArrayList<OrderDetail> orderDetails = new ArrayList<>();
            //使用雪花算法生成订单id
            long orderId = idWorker.nextId();
            //获取用户id
            Long userId = Long.valueOf(UserHolder.getUserId());
            order.setUserId(userId);
            order.setOrderId(orderId);
            order.setPaymentType(orderDTO.getPaymentType());
            //得到提交的购物车中的集合转成map结构的集合
            @NotNull List<CartDTO> carts = orderDTO.getCarts();
            //把carts的列表结构的集合转成map结构的集合
            Map<Long, Integer> cartsMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
            //收集carts中所有的skuId
            List<Long> skuId = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
            //得到所有的sku对象
            List<SkuDTO> skus = itemClient.findSkuBuSkuIds(skuId);
            //总金额：每个sku的price乘于购买数量
            Long totalFee = 0L;
            for (SkuDTO skuDTO : skus) {
                //商品单价
                Long price = skuDTO.getPrice();
                //商品数量
                Integer num = cartsMap.get(skuDTO.getId());
                totalFee += price*num;

                //把每个sku转成OrderDetails
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setOrderId(orderId);
                orderDetail.setSkuId(skuDTO.getId());
                orderDetail.setTitle(skuDTO.getTitle());
                orderDetail.setPrice(skuDTO.getPrice());
                orderDetail.setOwnSpec(skuDTO.getOwnSpec());
                orderDetail.setNum(num);
                orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
                orderDetail.setCreateTime(new Date());
                orderDetail.setUpdateTime(new Date());
                orderDetails.add(orderDetail);
            }
            order.setTotalFee(totalFee);
            order.setPostFee(0L);
            order.setActualFee(1L);//为了测试支付，先支付一分钱。
            order.setStatus(OrderStatusEnum.INIT.value());

            //保存订单
            orderMapper.insertSelective(order);

            //保存订单详情
            orderDetailMapper.insertList(orderDetails);

//            //创建订单物流信息
//            AddressDTO addressDTO = userClient.queryAddressById(userId, orderId);
//            OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
//            orderLogistics.setOrderId(orderId);
//
//            //保存订单物流信息
//            orderLogisticsMapper.insertSelective(orderLogistics);

            // 3 写orderLogistics
            // 3.1.查询收货地址
            AddressDTO addr = userClient.queryAddressById(userId, orderDTO.getAddressId());
            // 3.2.填写物流信息
            OrderLogistics logistics = BeanHelper.copyProperties(addr, OrderLogistics.class);
            logistics.setOrderId(orderId);

            int count = orderLogisticsMapper.insertSelective(logistics);
            if(count != 1){
                throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
            }

            //减库存
            itemClient.minusStock(cartsMap);
            return orderId;
        }catch (Exception e){
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    //查询订单
    public OrderVO queryOrderById(Long id) {
        //查询订单详情
        Order order = orderMapper.selectByPrimaryKey(id);

        //查询订单详情
        OrderDetail record=new OrderDetail();
        record.setId(id);
        List<OrderDetail> orderDetails = orderDetailMapper.select(record);

        //查询地址
        OrderLogistics orderLogistics = orderLogisticsMapper.selectByPrimaryKey(id);

        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        orderVO.setDetailList(BeanHelper.copyWithCollection(orderDetails,OrderDetailVO.class));
        orderVO.setLogistics(BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class));
        return orderVO;
    }

    //生成支付链接
    public String createWxUrl(Long id) {
        //判断redis中是否存有url链接
        String url = redisTemplate.opsForValue().get(WX_PAY_URL + id);
        if(StringUtils.isNotBlank(url)){
            return url;
        }
        //查询订单信息
        Order order = orderMapper.selectByPrimaryKey(id);
        if (order==null){
            //订单不存在
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        //获取微信二维码地址
        url = payHelper.createWxPayUrl(id, order.getActualFee());
        //把url放入到redis中，有效期为2小时
        redisTemplate.opsForValue().set(WX_PAY_URL + id, url, 2, TimeUnit.HOURS);
        return url;
    }

    //交易订单
    public void handlerOrder(Map<String, String> resultMa) {
        //验证通讯标识和业务标识
        payHelper.checkWxPayCode(resultMa);
        //获取微信返回的商家订单号和实付金额
        String WxOrderId = resultMa.get("out_trade_no");
        String WxTotalFee = resultMa.get("total_fee");
        //根据订单id查询订单
        Order order = orderMapper.selectByPrimaryKey(WxOrderId);
        if (order==null){
            //微信支付异常
            throw new LyException(ExceptionEnum.WX_PAY_ERROR);
        }
        //判断订单状态
        //初始化，未付款
        if (!order.getStatus().equals(OrderStatusEnum.INIT)){
            return;
        }
        //注意，Long类型的对象，如果比较是否相等或者大小，必须转成小写long数值。
        //因为Long类型的对象在数值范围超出-127~128之间就会比较两个对象的地址了。
        //另外，如果单比较是否相等，可以直接使用Long对象的equals方法
        if (!order.getActualFee().equals(Long.valueOf(WxTotalFee))){
            log.error("【微信支付回调失败！】金额不相符");
            throw new LyException(ExceptionEnum.WX_PAY_ERROR);
        }
        //修改订单状态
        Order record=new Order();
        record.setOrderId(order.getOrderId());
        //已付款，未发货
        record.setStatus(OrderStatusEnum.PAY_UP.value());
        record.setPayTime(new Date());
        orderMapper.updateByPrimaryKeySelective(record);
        log.info("【微信支付回调成功！】");
    }

    //支付状态查询
    public Integer queryPayStatus(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if(order == null){
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }


}
